package com.zc.util;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
import com.google.common.collect.ImmutableList;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * @author :  ville
 * @description : json操作封装
 * @createTime : 2019-07-05 14:39
 * @Version : 1.0.0
 * @Copyright : http://www.8atour.com
 * @modify : ville
 **/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class JsonUtil {
    private static final ObjectMapper mapper = new ObjectMapper();

    static {
        mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS, true); //忽略枚举大小写
        mapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT);
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        mapper.setDateFormat(new SimpleDateFormat(DateUtil.TIME_PATTERN));
        mapper.registerModule(new AfterburnerModule());
    }

    public static ObjectMapper getMapper() {
        return mapper;
    }

    /**
     * json 转 JsonNode
     *
     * @param jsonString
     * @return
     */
    @SneakyThrows(IOException.class)
    public static JsonNode toJsonNode(String jsonString) {
        return Optional.ofNullable(mapper.readTree(jsonString)).orElse(null);
    }

    /**
     * 从json中抽取子json
     *
     * @param fieldName  字段
     * @param jsonString 串
     * @return
     */
    public static JsonNode getJsonNode(String fieldName, String jsonString) {
        JsonNode jn = toJsonNode(jsonString);
        return jn != null ? jn.get(fieldName) : null;
    }

    /**
     * 从json中抽取子json,转Object
     *
     * @param fieldName  字段
     * @param jsonString 字符串
     * @return
     */
    public static <T> T fromJsonNode(String fieldName, String jsonString, Class<T> clazz) {
        JsonNode jn = getJsonNode(fieldName, jsonString);
        return jn != null ? fromJson(jn.get(fieldName).toString(), clazz) : null;
    }

    /**
     * 从json中抽取子json,转Object
     *
     * @param fieldName  字段
     * @param jsonString json字符串
     * @return object
     */
    public static <T> T fromJsonNode(String fieldName, String jsonString, TypeReference<T> tr) {
        JsonNode jn = getJsonNode(fieldName, jsonString);
        return jn != null ? fromJson(jn.get(fieldName).toString(), tr) : null;
    }

    /**
     * T 可以是List,Map
     *
     * @param <T>        object
     * @param jsonString json字符串
     * @param tr         类型type
     * @return object
     */
    @SneakyThrows(IOException.class)
    @SuppressWarnings("unchecked")
    public static <T> T fromJson(String jsonString, TypeReference<T> tr) {
        return (T) Optional.ofNullable(mapper.readValue(jsonString, tr)).orElse(null);
    }

    /**
     * Object可以是POJO，也可以是Collection或数组。 如果对象为Null, 返回"null". 如果集合为空集合, 返回"[]".
     *
     * @param object 对象
     * @return string   字符串
     */
    @SneakyThrows(IOException.class)
    public static String toJson(Object object) {
        return Optional.ofNullable(mapper.writeValueAsString(object)).orElse(null);
    }

    /**
     * 反序列化POJO或简单Collection如List<String>.
     * <p>
     * 如果JSON字符串为Null或"null"字符串, 返回Null. 如果JSON字符串为"[]", 返回空集合.
     * <p>
     * 如需反序列化复杂Collection如List<MyBean>, 请使用fromJson(String,JavaType)
     */
    @JsonCreator
    @SneakyThrows(IOException.class)
    public static <T> T fromJson(String jsonString, Class<T> clazz) {
        return Optional.ofNullable(mapper.readValue(jsonString, clazz)).orElse(null);
    }

    /**
     * 反序列化POJO或简单Collection如List<String>.
     * <p>
     * 如果JSON字符串为Null或"null"字符串, 返回Null. 如果JSON字符串为"[]", 返回空集合.
     * <p>
     * 如需反序列化复杂Collection如List<MyBean>, 请使用fromJson(String,JavaType)
     */
    @SneakyThrows(IOException.class)
    @JsonCreator
    public static <T> T fromJson(JsonNode jsonNode, Class<T> clazz) {
        return Optional.ofNullable(mapper.readValue(jsonNode.toString(), clazz)).orElse(null);
    }


    /**
     * 反序列化复杂Collection如List<Bean>,
     * 先使用函数createCollectionType构造类型,然后调用本函数.
     */
    @SneakyThrows(IOException.class)
    @SuppressWarnings("unchecked")
    public static <T> T fromJson(String jsonString, JavaType javaType) {
        return Optional.ofNullable((T) mapper.readValue(jsonString, javaType)).orElse(null);
    }

    /**
     * 反序列化复杂Collection如List<Bean>,
     * 先使用函数createCollectionType构造类型,然后调用本函数.
     */
    public static <T> List<T> fromJsonArray(JsonNode jsonNode, Class<T> clazz) {
        return fromJsonArray(toJson(jsonNode), clazz);
    }

    /**
     * 反序列化复杂Collection如List<Bean>,
     * 先使用函数createCollectionType构造类型,然后调用本函数.
     */
    @SneakyThrows(IOException.class)
    @SuppressWarnings("unchecked")
    public static <T> List<T> fromJsonArray(String json, Class<T> clazz) {
        return ImmutableList.copyOf((List<T>) Optional.ofNullable(mapper.readValue(json,
                getCollectionType(clazz))).orElse(Collections.emptyList()));
    }

    /**
     * 获取泛型的Collection Type
     *
     * @param elementClasses  元素类
     * @return JavaType Java类型
     * @since 1.0
     */
    private static JavaType getCollectionType(Class<?>... elementClasses) {
        return mapper.getTypeFactory().constructParametricType(List.class, elementClasses);
    }
}
